#ifndef XHIERARCHY_H
#define XHIERARCHY_H
#include <vector>
#include <memory>
#include <algorithm>

template<class T>
class XHierarchy : public std::enable_shared_from_this<XHierarchy<T>>
{
public:
    XHierarchy()
    {
        static_assert (std::is_base_of<XHierarchy,T>::value);
    }

    virtual ~XHierarchy() = default;
public:
    std::weak_ptr<T> getParent()const
    {
        return parent;
    }

    std::weak_ptr<T> getTopParent()const
    {
        std::shared_ptr<T> current = std::dynamic_pointer_cast<T>(XHierarchy<T>::shared_from_this());
        auto currentParent = current->getParent();
        while(true)
        {
            if(currentParent.expired())
                return current;
            else
            {
                current = currentParent.lock();
                currentParent = current->getParent();
            }
        }
    }

    void addChild(std::shared_ptr<T> child) {
        if (!child)
            return;

        if(!child->getParent().expired())
            child->getParent().lock()->removeChild(child);

        auto itr = std::find(children.begin(),children.end(),child);
        if(itr == children.end())
            children.push_back(child);

        child->parent = std::dynamic_pointer_cast<T>(std::enable_shared_from_this<XHierarchy<T>>::shared_from_this());
    }

    void removeChild(std::shared_ptr<T> child)
    {
        if(!child)
            return;

        auto itr = std::find(children.begin(),children.end(),child);
        children.erase(itr);
        child->parent.reset();
    }

    size_t getChildCount()const {return children.size();}
    bool hasChild()const{return !children.empty();}
    std::shared_ptr<T> getChildAt(size_t index)const {return children.at(index);}
protected:
    std::weak_ptr<T> parent;
    std::vector<std::shared_ptr<T>> children;
};

#endif // XHIERARCHY_H
